function def(val, defaults) {
	return val == undefined ? defaults : val;
}

function queryId(el, id) {
	return el.getElementById(id);
}

function query(el, className, useAll = false) {
	return useAll ? el.querySelectorAll(className) : el.querySelector(className);
}

function fix1(str) {
	return parseFloat(str.toFixed(1));
}

function fix2(str) {
	return parseFloat(str.toFixed(2));
}

function fix3(str) {
	return parseFloat(str.toFixed(3));
}

function lowercase(str) {
	return str.toLowerCase();
}

function removeHeadFootSlash(str) {
	return str.replace(/(\/{2,}$|^\/{2,})/g, '');
}

function removeHeadSlash(str) {
	return str.replace(/^\//g, '');
}

function removeLastSlash(str) {
	return str.replace(/\/$/g, '');
}

function removeAllSlash(str) {
	return str.replace(/\//g, '');
}

function ensureSlash(str) {
	return str.replace(/([^:]\/)\/+/g, '$1');
}

function uuid(len = 3) {
	// hashed string
	const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	let text = possible.charAt(~~(Math.random() * 51));
	for (let i = 1; i < len; i++) text += possible.charAt(~~(Math.random() * possible.length));
	return text;
}

function uustr() {
	// serial-ish str
	function strfy() {
		return Math.floor((1 + Math.random()) * 0x10000)
			.toString(16)
			.substring(1);
	}
	return `${strfy() + strfy()}-${strfy()}-${strfy()}-${strfy()}-${strfy() + strfy() + strfy()}`;
}

function ext(str) {
	// get extention
	return str
		.match(/\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/gim)[0]
		.replace(/\./, '')
		.toLowerCase();
}

function getCoords(el, e) {
	const x = !!e.touches ? e.touches[0].pageX : e.pageX;
	const y = !!e.touches ? e.touches[0].pageY : e.pageY;
	let left = el.offsetLeft;
	let top = el.offsetTop;
	while ((el = el.offsetParent)) {
		left += el.offsetLeft;
		top += el.offsetTop;
	}
	return {
		x: x - left,
		y: y - top
	};
}

function coords(evt, obj, offset) {
	// set mouse coords
	const ox = offset != null ? offset.x : 0;
	const oy = offset != null ? offset.y : 0;

	if (evt.targetTouches) {
		const targetTouches = evt.targetTouches;
		obj.x = targetTouches[0].pageX + ox;
		obj.y = targetTouches[0].pageY + oy;
	} else if (evt.pageX || evt.pageY) {
		obj.x = evt.pageX + ox;
		obj.y = evt.pageY + oy;
	} else {
		obj.x = evt.clientX + document.body.scrollLeft - document.body.clientLeft;
		obj.y = evt.clientY + document.body.scrollTop - document.body.clientTop;
	}
}

function hhmmss(totalSeconds) {
	// totalSeconds to hours/minutes/seconds
	const hh = Math.floor(totalSeconds / 3600);
	totalSeconds %= 3600;
	const mm = Math.floor(totalSeconds / 60);
	const ss = totalSeconds % 60;
	return {
		hh: hh < 10 ? `0${hh}` : hh.toString(),
		mm: mm < 10 ? `0${mm}` : mm.toString(),
		ss: ss < 10 ? `0${ss}` : ss.toString()
	};
}

function formatBytes(bytes) {
	if (bytes <= 0) return 'N/A';
	const units = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
	const exponent = Math.min(Math.floor(Math.log10(bytes) / 3), units.length - 1);
	bytes = Number((bytes / 1000 ** exponent).toPrecision(3));
	return bytes + units[exponent];
}

function formatDuration(seconds) {
	// seconds -> return '00:00' format
	const m = Math.floor(seconds / 60);
	const s = Math.floor(seconds - m * 60);
	const mm = m < 10 ? `0${m.toString()}` : m.toString();
	const ss = s < 10 ? `0${s.toString()}` : s.toString();
	return `${mm}:${ss}`;
}

function capitalize(str) {
	return str.toLowerCase().replace(/\b(\w)|\s(\w)/g, (m) => m.toUpperCase());
}

function digitfy(num, unit = 2) {
	// get -> 3 to '003'
	let str = parseInt(num).toString();
	let i = 0;
	while (i < unit) {
		str = `0${str}`;
		i++;
	}
	return str.substr(str.length - unit, str.length);
}

function hyphenfy(str) {
	// replace symbols with hypen
	str = str.toLowerCase().replace(/[\s-!$%#^&*()_@+|~=`{}\[\]:";'<>?,.\/\\]/g, '-');
	return str.replace(/\-(\-*)/g, '-').replace(/\-$/gi, '');
}

function dashfy(str) {
	// break camelString with dash
	return str
		.replace(/([a-z])([A-Z])/g, '$1-$2')
		.replace(/[ \t\W]/g, '-')
		.replace(/^-+|-+$/g, '')
		.toLowerCase();
}

function breakSpace(str) {
	return str.replace(/\s/g, '\n').replace(/\s\n/g, '');
}

function breakString(string, breakPoint = 4, breakRatio = 0.7) {
	const words = string.replace(/(\s|\t)+/gi, ' ').split(' ');
	const cut = words.length < breakPoint ? breakPoint : Math.round(words.length * breakRatio);
	let msg = '';

	if (words.length > cut) {
		for (let i = 0; i < words.length; i++) {
			if (i < cut) {
				msg += words[i] + (i == cut - 1 ? '' : ' ');
			} else if (i == cut) {
				msg += `<br/>${words[i]}`;
			} else if (i > cut) {
				msg += ` ${words[i]}`;
			}
		}
	} else {
		msg = string;
	}
	return msg;
}

export {
	def,
	queryId,
	query,
	fix1,
	fix2,
	fix3,
	lowercase,
	removeHeadFootSlash,
	removeHeadSlash,
	removeLastSlash,
	removeAllSlash,
	ensureSlash,
	uuid,
	uustr,
	ext,
	getCoords,
	coords,
	hhmmss,
	formatBytes,
	formatDuration,
	capitalize,
	digitfy,
	hyphenfy,
	dashfy,
	breakSpace,
	breakString
};
